#include "Shader.h"
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
using namespace glm;
typedef unsigned int uint;

Shader::Shader(const char *vpth, const char *fpth)
{
	string vCode, fCode;
	ifstream vFile, fFile;
	vFile.exceptions(ifstream::failbit | ifstream::badbit);
	fFile.exceptions(ifstream::failbit | ifstream::badbit);
	try
	{
		vFile.open(vpth);
		fFile.open(fpth);
		stringstream vStr, fStr;
		vStr << vFile.rdbuf();
		fStr << fFile.rdbuf();
		fFile.close();
		vFile.close();
		vCode = vStr.str();
		fCode = fStr.str();
	}
	catch (ifstream::failure e)
	{
		cout << e.what() << endl;
	}
	const char *vScode = vCode.c_str(), *fScode = fCode.c_str();
	uint vertex, fragment;
	int success;
	char infoLog[512];

	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vScode, NULL);
	glCompileShader(vertex);
	glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertex, 512, NULL, infoLog);
		cout << "ERROR::SHADER::VERTEX::COMPILATION_ERROR\n"
			 << infoLog << endl;
		exit(-1);
	}
	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fScode, NULL);
	glCompileShader(fragment);
	glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragment, 512, NULL, infoLog);
		cout << "ERROR::SHADER::FRAGMENT::COMPILATION_ERROR\n"
			 << infoLog << endl;
		exit(-1);
	}
	ID = glCreateProgram();
	glAttachShader(ID, vertex);
	glAttachShader(ID, fragment);
	glLinkProgram(ID);
	glGetShaderiv(ID, GL_LINK_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(ID, 512, NULL, infoLog);
		cout << "ERROR::SHADER::LINKING_ERROR\n"
			 << infoLog << endl;
		exit(-1);
	}
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

uint Shader::id()
{
	return ID;
}

void Shader::use()
{
	glUseProgram(ID);
}

void Shader::setUniform(const char *name, int v1)
{

	glUniform1i(glGetUniformLocation(ID, name), v1);
}

void Shader::setUniform(const char *name, int v1, int v2)
{
	glUniform2i(glGetUniformLocation(ID, name), v1, v2);
}

void Shader::setUniform(const char *name, int v1, int v2, int v3)
{
	glUniform3i(glGetUniformLocation(ID, name), v1, v2, v3);
}

void Shader::setUniform(const char *name, int v1, int v2, int v3, int v4)
{
	glUniform4i(glGetUniformLocation(ID, name), v1, v2, v3, v4);
}

void Shader::setUniform(const char *name, float v1)
{
	glUniform1f(glGetUniformLocation(ID, name), v1);
}

void Shader::setUniform(const char *name, float v1, float v2)
{
	glUniform2f(glGetUniformLocation(ID, name), v1, v2);
}

void Shader::setUniform(const char *name, float v1, float v2, float v3)
{
	glUniform3f(glGetUniformLocation(ID, name), v1, v2, v3);
}

void Shader::setUniform(const char *name, float v1, float v2, float v3, float v4)
{
	glUniform4f(glGetUniformLocation(ID, name), v1, v2, v3, v4);
}

void Shader::setMat4(const char *name, mat4 mt)
{
	glUniformMatrix4fv(glGetUniformLocation(ID, name), 1, GL_FALSE, value_ptr(mt));
}